package cn.tedu.csmall.passport.service.impl;

import cn.tedu.csmall.passport.ex.ServiceException;
import cn.tedu.csmall.passport.mapper.AdminMapper;
import cn.tedu.csmall.passport.mapper.AdminRoleMapper;
import cn.tedu.csmall.passport.pojo.dto.AdminAddNewDTO;
import cn.tedu.csmall.passport.pojo.dto.AdminLoginDTO;
import cn.tedu.csmall.passport.pojo.entity.Admin;
import cn.tedu.csmall.passport.pojo.entity.AdminRole;
import cn.tedu.csmall.passport.pojo.vo.AdminListItemVO;
import cn.tedu.csmall.passport.pojo.vo.AdminStandardVO;
import cn.tedu.csmall.passport.security.AdminDetails;
import cn.tedu.csmall.passport.service.IAdminService;
import cn.tedu.csmall.passport.web.ServiceCode;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class AdminServiceImpl implements IAdminService {

    @Autowired
    AdminMapper adminMapper;
    @Autowired
    AdminRoleMapper adminRoleMapper;
    @Autowired
    PasswordEncoder passwordEncoder;
    @Autowired
    AuthenticationManager authenticationManager;
    @Value("${csmall.jwt.secret-key}")
    String secretKey;
    @Value("${csmall.jwt.duration-in-day}")
    long durationInDay;

    public AdminServiceImpl() {
        System.out.println("创建业务实现类：AdminServiceImpl");
    }

    @Override
    public String login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理【管理员登录】业务，参数：{}",adminLoginDTO);
        //封装登录信息？？？？
        Authentication authentication = new UsernamePasswordAuthenticationToken(adminLoginDTO.getUsername(),adminLoginDTO.getPassword());//放置用户名，密码，权限
        // 调用AuthenticationManager对象的authenticate()方法处理认证,将客户端的信息和数据库查出来的信息做对比
        Authentication authenticateResult = authenticationManager.authenticate(authentication);
        log.debug("执行认证成功,AuthenticationManager的参数：{}",authenticateResult);
        //获取到AdminDetails类,authenticateResult中包含了AdminDetails类
        Object principal = authenticateResult.getPrincipal();
        log.debug("principal的类型：{}",principal.getClass().getName());
        log.debug("principal的参数：{}",principal);
        // 将principal强转为AdminDetails 类型
        AdminDetails adminDetails = (AdminDetails) principal;

        //令牌的用户信息
        Map<String ,Object> claims = new HashMap<>();
        claims.put("id",adminDetails.getId());
        claims.put("username",adminDetails.getUsername());
        claims.put("authorities", JSON.toJSONString(adminDetails.getAuthorities()));
        //以下为测试，验证adminDetails.getAuthorities()的属性
        //authorities的参数=[/pms/product/add-new, /pms/product/delete, /pms/product/read, /pms/product/update]
        log.debug("authorities的参数={}",adminDetails.getAuthorities());
        //authorities的类型=java.util.Collections$UnmodifiableSet
        log.debug("authorities的类型={}",adminDetails.getAuthorities().getClass().getName());

//        Date expirationDate = new Date(System.currentTimeMillis() + 10 * 24 * 60 * 60 * 1000);
        Date expirationDate = new Date(System.currentTimeMillis() + durationInDay * 24 * 60 * 60 * 1000);
        System.out.println("过期时间：" + expirationDate);

        /*生成令牌*/
        //通过配置设置secretKey内容
//        String secretKey = "asdfasdfasdfJJSADJFWE";
        String jwt = Jwts.builder()
                //Header，设置选择哪套令牌
                .setHeaderParam("alg","HS256")
                .setHeaderParam("typ","JWT")
                //Payload
                .setClaims(claims)//设置内容
                .setExpiration(expirationDate)//设置过期时间
                //Signature
                .signWith(SignatureAlgorithm.HS256,secretKey)//签名
                //整合
                .compact();
        log.debug("返回jwt的参数：{}",jwt);
        return jwt;
    }

    @Override
    public void addNew(AdminAddNewDTO adminAddNewDTO) {
        log.debug("开始处理【添加管理员】业务，参数：{}",adminAddNewDTO);
        String username = adminAddNewDTO.getUsername();
        String phone = adminAddNewDTO.getPhone();
        String email = adminAddNewDTO.getEmail();
        Long[] roleIds = adminAddNewDTO.getRoleIds();

        log.debug("检查选择的角色是否合法");
        for (int i = 0; i < roleIds.length; i++) {
            if(roleIds[i] == 1){
                String message = "添加管理员失败，非法访问！！！";
                log.error(message);
                throw new ServiceException(ServiceCode.ERR_INSERT,message);
            }
        }

        log.debug("检测用户名是否被占用");
        if(adminMapper.countByUsername(username) != 0){
            String message = "用户名已存在，请更换用户名再尝试";
            log.error(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT_USERNAME,message);
        }
        log.debug("检测手机号是否被占用");
        if(adminMapper.countByPhone(phone) != 0){
            String message = "手机号已存在，请更换手机号再尝试";
            log.error(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT_PHONE,message);
        }
        log.debug("检测电子邮箱是否被占用");
        if(adminMapper.countByEmail(email) != 0){
            String message = "电子邮箱已存在，请更换电子邮箱再尝试";
            log.error(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT_EMAIL,message);
        }

        Admin admin = new Admin();
        BeanUtils.copyProperties(adminAddNewDTO,admin);
        // 从Admin对象中取出密码，进行加密处理，并将密文封装回Admin对象中
        String rawPassword = admin.getPassword();
        String encodePassword = passwordEncoder.encode(rawPassword);
        admin.setPassword(encodePassword);
        //补全Admin对象的属性值
        admin.setLoginCount(0);

        log.debug("即将添加管理员数据");
        int rows = adminMapper.insert(admin);
        String message = "添加管理员失败，服务器忙，请稍后再试";
        if(rows != 1){
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT,message);
        }
        log.debug("添加管理员完成，受影响行数：{}",rows);

        List<AdminRole> adminRoleList = new ArrayList<>();
        Long[] adminIds = adminAddNewDTO.getRoleIds();
        Long id = admin.getId();
        for (int i = 0; i < adminIds.length; i++) {
            AdminRole adminRole = new AdminRole();
            adminRole.setAdminId(id).setRoleId(adminIds[i]);
            adminRoleList.add(adminRole);
        }
        log.debug("即将添加管理员与角色关系数据");
        rows = adminRoleMapper.insertBatch(adminRoleList);
        if(rows != adminIds.length){
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT,message);
        }
        log.debug("添加管理员与角色关系完成，受影响行数：{}",rows);
    }

    //检查：数据是否存在
    @Override
    public void deleteById(Long id) {
        int result = adminMapper.countById(id);
        if(result == 0){
            String message = "删除管理员失败，管理员id不存在，请更换id再尝试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }
        log.debug("即将删除管理员数据");
        int rows = adminMapper.deleteById(id);
        if(rows != 1){
            String message = "删除管理员失败，服务器忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE,message);
        }
        log.debug("删除管理员数据完成受影响行数：{}",rows);

        // 完善删除管理员表操作，admin_role表也要删除
        log.debug("即将删除管理员与角色关系数据");
        rows = adminRoleMapper.deleteById(id);
        if(rows <1){
            String message = "删除管理员失败，服务器忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE,message);
        }
        log.debug("删除管理员与角色关系数据完成，受影响行数：{}",rows);
    }

    @Override
    public void setEnable(Long id) {
        updateEnableById(id,1);
    }

    @Override
    public void setDisable(Long id) {
        updateEnableById(id,0);
    }

    //检查：是否为空，状态是否相同
    private void updateEnableById(Long id,Integer enable ){
        String[] tips = {"禁用","启用"};
        log.debug("开始处理修改【id={}的管理员】为{}状态的业务",id,tips[enable]);
        AdminStandardVO queryResult = adminMapper.getStandardById(id);
        if(queryResult == null){
            String message = tips[enable] + "管理员失败，数据不存在";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
        }

        if(queryResult.getEnable() == enable){
            String message = tips[enable] + "管理员失败，该账号已处于" + tips[enable]+ "状态";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT_ENABLE,message);
        }

        //开始修改启用状态
        Admin admin = new Admin();
        admin.setId(id).setEnable(enable);
        int rows = adminMapper.updateById(admin);
        if(rows != 1){
            String message = tips[enable] + "管理员失败，服务器忙，请稍后再试";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE,message);
        }
        log.debug(tips[enable] + "管理员完成，受影响行数：{}",rows);
    }

    //检查：除去 id=1 的系统管理员
    @Override
    public List<AdminListItemVO> list() {
        log.debug("开始处理查询管理员列表业务");
        List<AdminListItemVO> adminList = adminMapper.list();
        /*//第一种做法，直接将列表第一个数据移除，因为列表排序是根据id升序进行的
        adminList.remove(0);*/
        Iterator<AdminListItemVO> iterator = adminList.iterator();
        while (iterator.hasNext()){
            AdminListItemVO itemVO = iterator.next();
            if(itemVO.getId() == 1){
                iterator.remove();
                break;
            }
        }
        return adminList;
    }
}
